package com.kexilo.system.management.controller.monitor;

import com.kexilo.core.common.core.web.domain.R;
import com.kexilo.core.shared.cache.CacheMonitor;
import io.swagger.v3.oas.annotations.Operation;

import java.util.HashMap;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 缓存监控
 * 
 * @author Kexilo
 */
@RestController
@RequestMapping("/monitor/cache")
@Tag(name = "缓存监控", description = "缓存监控相关接口")
public class CacheController {
    
    private static final Logger log = LoggerFactory.getLogger(CacheController.class);

    @Autowired
    private CacheMonitor cacheMonitor;

    @Autowired
    private CacheManager cacheManager;

    @Autowired(required = false)
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取缓存统计信息
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/stats")
    @Operation(summary = "获取缓存统计信息", description = "获取缓存命中率、大小等统计信息")
    public R<Map<String, Object>> getCacheStats() {
        try {
            Map<String, Object> result = new HashMap<>(cacheMonitor.getCachePerformanceReport());
            return R.success(result);
        } catch (Exception e) {
            log.error("获取缓存统计信息失败", e);
            return R.fail("获取缓存统计信息失败");
        }
    }

    /**
     * 获取缓存列表
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/list")
    @Operation(summary = "获取缓存列表", description = "获取所有缓存名称和基本信息")
    public R<List<Map<String, Object>>> getCacheList() {
        try {
            List<Map<String, Object>> cacheList = new ArrayList<>();
            
            Collection<String> cacheNames = cacheManager.getCacheNames();
            for (String cacheName : cacheNames) {
                Cache cache = cacheManager.getCache(cacheName);
                if (cache != null) {
                    Map<String, Object> cacheInfo = new HashMap<>();
                    cacheInfo.put("cacheName", cacheName);
                    cacheInfo.put("cacheType", cache.getClass().getSimpleName());
                    
                    if (cache instanceof CaffeineCache) {
                        CaffeineCache caffeineCache = (CaffeineCache) cache;
                        com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache = 
                            caffeineCache.getNativeCache();
                        
                        cacheInfo.put("size", nativeCache.estimatedSize());
                        cacheInfo.put("hitCount", nativeCache.stats().hitCount());
                        cacheInfo.put("missCount", nativeCache.stats().missCount());
                        cacheInfo.put("hitRate", nativeCache.stats().hitRate());
                    } else {
                        cacheInfo.put("size", "N/A");
                        cacheInfo.put("hitCount", "N/A");
                        cacheInfo.put("missCount", "N/A");
                        cacheInfo.put("hitRate", "N/A");
                    }
                    
                    cacheList.add(cacheInfo);
                }
            }
            
            return R.success(cacheList);
        } catch (Exception e) {
            log.error("获取缓存列表失败", e);
            return R.fail("获取缓存列表失败");
        }
    }

    /**
     * 获取Redis信息
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/redis/info")
    @Operation(summary = "获取Redis信息", description = "获取Redis服务器信息和统计数据")
    public R<Map<String, Object>> getRedisInfo() {
        if (redisTemplate == null) {
            return R.fail("Redis未配置");
        }
        
        try {
            Map<String, Object> redisInfo = new HashMap<>();
            
            // Redis基本信息
            Properties info = redisTemplate.getConnectionFactory()
                .getConnection().info();
            
            redisInfo.put("version", info.getProperty("redis_version"));
            redisInfo.put("mode", info.getProperty("redis_mode"));
            redisInfo.put("port", info.getProperty("tcp_port"));
            redisInfo.put("uptime", info.getProperty("uptime_in_seconds"));
            
            // 内存信息
            Map<String, Object> memory = new HashMap<>();
            memory.put("used", info.getProperty("used_memory_human"));
            memory.put("peak", info.getProperty("used_memory_peak_human"));
            memory.put("fragmentation", info.getProperty("mem_fragmentation_ratio"));
            redisInfo.put("memory", memory);
            
            // 连接信息
            Map<String, Object> clients = new HashMap<>();
            clients.put("connected", info.getProperty("connected_clients"));
            clients.put("blocked", info.getProperty("blocked_clients"));
            redisInfo.put("clients", clients);
            
            // 统计信息
            Map<String, Object> stats = new HashMap<>();
            stats.put("keyspace_hits", info.getProperty("keyspace_hits"));
            stats.put("keyspace_misses", info.getProperty("keyspace_misses"));
            stats.put("expired_keys", info.getProperty("expired_keys"));
            stats.put("evicted_keys", info.getProperty("evicted_keys"));
            redisInfo.put("stats", stats);
            
            return R.success(redisInfo);
        } catch (Exception e) {
            log.error("获取Redis信息失败", e);
            return R.fail("获取Redis信息失败");
        }
    }

    /**
     * 清除指定缓存
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
    @DeleteMapping("/clear/{cacheName}")
    @Operation(summary = "清除指定缓存", description = "清除指定名称的缓存")
    public R<Void> clearCache(@PathVariable String cacheName) {
        try {
            Cache cache = cacheManager.getCache(cacheName);
            if (cache != null) {
                cache.clear();
                log.info("清除缓存: {}", cacheName);
                return R.success("缓存清除成功");
            } else {
                return R.fail("缓存不存在");
            }
        } catch (Exception e) {
            log.error("清除缓存失败", e);
            return R.fail("清除缓存失败");
        }
    }

    /**
     * 清除所有缓存
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
    @DeleteMapping("/clear/all")
    @Operation(summary = "清除所有缓存", description = "清除所有缓存数据")
    public R<Void> clearAllCache() {
        try {
            Collection<String> cacheNames = cacheManager.getCacheNames();
            for (String cacheName : cacheNames) {
                Cache cache = cacheManager.getCache(cacheName);
                if (cache != null) {
                    cache.clear();
                }
            }
            log.info("清除所有缓存");
            return R.success("所有缓存清除成功");
        } catch (Exception e) {
            log.error("清除所有缓存失败", e);
            return R.fail("清除所有缓存失败");
        }
    }

    /**
     * 重置缓存统计
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:edit')")
    @PostMapping("/reset")
    @Operation(summary = "重置缓存统计", description = "重置缓存统计信息")
    public R<Void> resetCacheStats() {
        try {
            cacheMonitor.resetStatistics();
            return R.success("缓存统计重置成功");
        } catch (Exception e) {
            log.error("重置缓存统计失败", e);
            return R.fail("重置缓存统计失败");
        }
    }

    /**
     * 获取缓存键值
     */
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/keys/{cacheName}")
    @Operation(summary = "获取缓存键值", description = "获取指定缓存的所有键值")
    public R<List<String>> getCacheKeys(@PathVariable String cacheName) {
        try {
            Cache cache = cacheManager.getCache(cacheName);
            if (cache == null) {
                return R.fail("缓存不存在");
            }

            List<String> keys = new ArrayList<>();
            
            if (cache instanceof CaffeineCache) {
                CaffeineCache caffeineCache = (CaffeineCache) cache;
                com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache = 
                    caffeineCache.getNativeCache();
                
                // Caffeine缓存无法直接获取所有键，返回统计信息
                keys.add("Caffeine缓存无法获取具体键值，当前大小: " + nativeCache.estimatedSize());
            }
            
            return R.success(keys);
        } catch (Exception e) {
            log.error("获取缓存键值失败", e);
            return R.fail("获取缓存键值失败");
        }
    }
}

